﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AAA.DataSource;
using AAA.Meta.Quote.Data;
using AAA.DesignPattern.Observer;
using AAA.TradeLanguage.Data;

namespace AAA.TradeLanguage
{
    public abstract class AbstractSignal : DefaultDataAccess, ISignal, IObserver
    {
        private PositionManager _positionManager;
        private IFunctionMeta _functionMeta;
        private BarCompression _barCompression;
        private string _strBaseSymbolId;
        private SignalManager _signalManager;
        private Subject _subject;

        private List<SignalInfo> _lstNextBarOpen;        
        private List<SignalInfo> _lstThisBarClose;

        private string _strVariableName;
        private string _strSignalGroupName;

        private int _iOffset;

        public int Offset
        {
            get { return _iOffset; }
            set { _iOffset = value; }
        }

        public string SignalGroupName
        {
            get { return _strSignalGroupName; }
            set { _strSignalGroupName = value; }
        }

        protected float Variable(string strName)
        {
            return Variable(strName, 0);
        }

        protected void Variable(string strName, float fValue)
        {
            BarRecord barRecord;
            BarCompression barCompression;  

            barRecord = new BarRecord();
            barCompression = BarCompression(BaseSymbolId);
            barRecord.BarCompression = barCompression.DataCompression;
            barRecord.CompressionInterval = barCompression.Interval;
            barRecord.BarDateTime = Time(BaseSymbolId, 0);
            barRecord[strName] = fValue;
            AddBarData(_strVariableName, barRecord);
/*
            BarRecord barRecord = Bar(_strVariableName, 0);
            barRecord[strName] = fValue;            
 */ 
        }

        protected int VariableBarNumber()
        {
            return BarNumber(_strVariableName, 0);
        }

        protected float Variable(string strName,int iIndex)
        {
            BarRecord barRecord = Bar(_strVariableName, iIndex);

            return barRecord != null ? barRecord[strName] : float.NaN;
        }

        protected IFunction InitFunction(IFunction funciton)
        {
            funciton.SetCurrentTime(CurrentTime);
            funciton.BaseSymbolId = BaseSymbolId;
            return funciton;
        }

        public AbstractSignal()
        {
            _functionMeta = new DefaultFunctionMeta();
            _signalManager = new SignalManager();
            _lstNextBarOpen = new List<SignalInfo>();
            _lstThisBarClose = new List<SignalInfo>();
            _subject = new Subject();
            _signalManager.Attach(this);
            OnDataSourceChange += new DataSourceChangeEvent(DataSourceChange);
            MinEntryPosition = 1;
            MaxPosition = 1;
            _strVariableName = DisplayName + DateTime.Now.Ticks.ToString();
        }

        private void DataSourceChange(IDataSource oldDataSource, IDataSource newDataSource)
        {
            if (oldDataSource != null)
                oldDataSource.Detach(this);

            if (newDataSource != null)
                newDataSource.Attach(this);

        }

        #region ISignal 成員
        public int MinEntryPosition
        {
            get 
            { 
                return _signalManager.MinEntryPosition; 
            }
            
            set 
            {
                _signalManager.MinEntryPosition = value; 
            }
        }

        public int MaxPosition
        {
            get
            {
                return _signalManager.MaxPosition;
            }
            set
            {
                _signalManager.MaxPosition = value;
            }
        }

        public PositionManager PositionManager
        {
            get
            {
                return _positionManager;
            }

            set
            {
                _positionManager = value;
            }
        }

        public string BaseSymbolId
        {
            get
            {
                return _strBaseSymbolId;
            }

            set
            {
                _strBaseSymbolId = value;
                ActiveSymbol = value;
                _barCompression = BarCompression(_strBaseSymbolId);
            }
        }

        public BarCompression DataCompression
        {
            get
            {
                return _barCompression;
            }
        }

        public void SetCurrentTime(CurrentTime currentTime)
        {
            CurrentTime = currentTime;
            DataSource = currentTime.DataSource;
            _barCompression = BarCompression(_strBaseSymbolId);
        }


        public void BeforeSignal()
        {

//            if (_needCalculate == false)
//                return;

            SignalInfo signalInfo;
            DateTime dtCurrent;
            try
            {
                for (int i = _lstNextBarOpen.Count - 1; i >= 0; i--)
                {
                    signalInfo = _lstNextBarOpen[i];
                    dtCurrent = Time(signalInfo.BaseSymbolId, 0);
                    if (Time(signalInfo.BaseSymbolId, 0).CompareTo(signalInfo.TimeForActive) >= 0)
                    {
                        if(signalInfo.OrderType == OrderTypeEnum.MarketOrder)
                            signalInfo.Price = Open(signalInfo.BaseSymbolId, 0);
                        _lstNextBarOpen.RemoveAt(i);
                        signalInfo.TimePlaced = Time(signalInfo.BaseSymbolId, 0);//CurrentTime.CurrentDateTime;
                        _signalManager.AddActiveSignal(signalInfo);
                    }
                    _signalManager.MatchPrice(Open(signalInfo.BaseSymbolId, 0));
                }
/*
                fClosePrice = Open(BaseSymbolId, 0);
                for (int i = _lstNextBar.Count - 1; i >= 0; i--)
                {
                    signalInfo = _lstNextBar[i];
                    if (signalInfo.PriceTimeType == PriceTimeTypeEnum.AtNextBarOpen)
                    {
                        signalInfo.OrderType = OrderTypeEnum.LimitOrder;
                        signalInfo.Price = fClosePrice;
                    }
                    _lstNextBar.RemoveAt(i);
                    AddActiveSignal(signalInfo);
                }
                _signalManager.MatchPrice(fClosePrice);
                _needCalculate = false;
 */ 
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void Calculate()
        {
            BeforeSignal();
            ExecCalculate();
            AfterSignal();
        }

        public abstract void ExecCalculate();

        public void AfterSignal()
        {
            SignalInfo signalInfo;
            
            try
            {
                for (int i = _lstThisBarClose.Count - 1; i >= 0; i--)
                {
                    signalInfo = _lstThisBarClose[i];
                    if (Time(signalInfo.BaseSymbolId, 0).CompareTo(signalInfo.TimeForActive) >= 0)
                    {
                        signalInfo.Price = Close(signalInfo.BaseSymbolId, 1);
                        signalInfo.TimePlaced = Time(signalInfo.BaseSymbolId, 0);
                        _lstThisBarClose.RemoveAt(i);
                        _signalManager.AddActiveSignal(signalInfo);
                    }
                }

/*
                if (CurrentTime.CurrentDateTime.ToString("yyyy/MM/dd HH:mm:ss") == CurrentTime.CurrentBarTime(CurrentTime.CurrentDateTime, BarCompression(BaseSymbolId)).AddSeconds(-1).ToString("yyyy/MM/dd HH:mm:ss"))
                {
                    fClosePrice = Close(BaseSymbolId, 0);
                    for(int i = _lstThisBarClose.Count - 1; i >= 0; i--)
                    {
                        signalInfo = _lstThisBarClose[i];
                        signalInfo.OrderType = OrderTypeEnum.LimitOrder;
                        signalInfo.Price = fClosePrice;
                        _lstThisBarClose.RemoveAt(i);
                        AddActiveSignal(signalInfo);
                    }
                    _signalManager.MatchPrice(fClosePrice);
                    _needCalculate = true; 
                }
 */
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private SignalInfo CreateSignalInfo(string strName, PriceTimeTypeEnum ePriceTimeType, OrderTypeEnum eOrderType, float fPrice)
        {
            SignalInfo signalInfo = new SignalInfo();

            try
            {
                signalInfo.SignalGroupName = SignalGroupName;
                signalInfo.SignalName = strName;                
                signalInfo.BaseSymbolId = BaseSymbolId;
                signalInfo.OrderType = eOrderType;
                signalInfo.PriceTimeType = ePriceTimeType;
                signalInfo.Price = fPrice;
                return signalInfo;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void AddActiveSignal(SignalInfo signalInfo)
        {
            DateTime dtCurrentTime = CurrentTime.CurrentDateTime;

            switch (signalInfo.PriceTimeType)
            {
                case PriceTimeTypeEnum.AtThisBar:
                    signalInfo.TimeForActive = Time(signalInfo.BaseSymbolId, 1);
                    _signalManager.AddActiveSignal(signalInfo);
                    break;

                case PriceTimeTypeEnum.AtNextBar:
                case PriceTimeTypeEnum.AtNextBarOpen:
                    signalInfo.TimeForActive = Time(signalInfo.BaseSymbolId, 0);                    
                    if(signalInfo.PriceTimeType == PriceTimeTypeEnum.AtNextBarOpen)
                        signalInfo.OrderType = OrderTypeEnum.MarketOrder;
                    _lstNextBarOpen.Add(signalInfo);
                    break;

                case PriceTimeTypeEnum.AtThisBarClose:
                    signalInfo.TimeForActive = Time(signalInfo.BaseSymbolId, 0).AddSeconds(-1);
                    signalInfo.OrderType = OrderTypeEnum.MarketOrder;
                    _lstThisBarClose.Add(signalInfo);
                    break;
            }

        }

        public void LongEntry(string strName, PriceTimeTypeEnum ePriceTimeType, OrderTypeEnum eOrderType, float fPrice)
        {
            SignalInfo signalInfo = CreateSignalInfo(strName, ePriceTimeType, eOrderType, fPrice);

            try
            {                                
                signalInfo.OrderDirection = OrderDirectionEnum.LongEntry;
                AddActiveSignal(signalInfo);                
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void ShortEntry(string strName, PriceTimeTypeEnum ePriceTimeType, OrderTypeEnum eOrderType, float fPrice)
        {
            SignalInfo signalInfo = CreateSignalInfo(strName, ePriceTimeType, eOrderType, fPrice);

            try
            {
                signalInfo.OrderDirection = OrderDirectionEnum.ShortEntry;
                AddActiveSignal(signalInfo);                
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        public void LongExit(string strName, PriceTimeTypeEnum ePriceTimeType, OrderTypeEnum eOrderType, float fPrice)
        {
            SignalInfo signalInfo = CreateSignalInfo(strName, ePriceTimeType, eOrderType, fPrice);

            try
            {
                signalInfo.OrderDirection = OrderDirectionEnum.LongExit;
                AddActiveSignal(signalInfo);
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        public void ShortExit(string strName, PriceTimeTypeEnum ePriceTimeType, OrderTypeEnum eOrderType, float fPrice)
        {
            SignalInfo signalInfo = CreateSignalInfo(strName, ePriceTimeType, eOrderType, fPrice);

            try
            {
                signalInfo.OrderDirection = OrderDirectionEnum.ShortExit;
                AddActiveSignal(signalInfo);
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        public void TrailingStop(float fPoint)
        {
            throw new NotImplementedException();
        }

        public void VolumeStop(float fVolume)
        {
            throw new NotImplementedException();
        }

        public void SingleBarStop(float fPoint)
        {
            throw new NotImplementedException();
        }

        public List<SignalRecord> TradeRecord()
        {
            return _signalManager.TradeRecord();
        }

        #endregion

        #region IObserver 成員

        public void Update(object oSource, AAA.DesignPattern.Observer.IMessageInfo miMessage)
        {
            switch (miMessage.MessageSubject)
            {
                case "Filled":
                case "Active":
                case "Canceled":
                case "Open":
                    Notify(miMessage);
                    break;

                default:
                    if((BarCompression(BaseSymbolId) == null) ||
                       (DataSource.ContainsSymbol(BaseSymbolId) == false))
                    {
                        IsActive = false;
                        ErrorMessage = "DataSource doesn't contain the symbol (" + BaseSymbolId + ")";
                        break;
                    }

                    Calculate();
                    break;
            }
        }

        #endregion

        #region ISubject 成員

        public void Attach(AAA.DesignPattern.Observer.IObserver observer)
        {
            _subject.Attach(observer);
        }

        public void Detach(AAA.DesignPattern.Observer.IObserver observer)
        {
            _subject.Detach(observer);
        }

        public void Notify(AAA.DesignPattern.Observer.IMessageInfo miMessage)
        {
            _subject.Notify(miMessage);
        }

        #endregion


        #region IFunctionMeta Members

        public bool IsActive
        {
            get
            {
                return _functionMeta.IsActive;
            }

            set
            {
                _functionMeta.IsActive = value;
            }
        }

        public string ErrorMessage
        {
            get
            {
                return _functionMeta.ErrorMessage;
            }
            set
            {
                _functionMeta.ErrorMessage = value;
            }
        }

        public string DisplayName
        {
            get
            {
                return _functionMeta.DisplayName;
            }
            set
            {
                _functionMeta.DisplayName = value; ;
            }
        }

        public string[] InputVariableNames
        {
            get
            {
                return _functionMeta.InputVariableNames;
            }
            set
            {
                _functionMeta.InputVariableNames = value;
            }
        }

        public string[] InputVariableDescs
        {
            get
            {
                return _functionMeta.InputVariableDescs;
            }
            set
            {
                _functionMeta.InputVariableDescs = value;
            }
        }

        public object[] DefaultValues
        {
            get
            {
                return _functionMeta.DefaultValues;
            }
            set
            {
                _functionMeta.DefaultValues = value;
            }
        }

        public void InputVariable(string strName, object oValue)
        {
            _functionMeta.InputVariable(strName, oValue);
        }

        public object InputVariable(string strName)
        {
            return _functionMeta.InputVariable(strName);
        }

        public void MatchPrice(float fPrice)
        {
            _signalManager.MatchPrice(fPrice);
        }

        public void ResetPerformance()
        {
            try
            {
                DataSource.RemoveSymbol(_strVariableName);
                _signalManager.Reset();
                _lstNextBarOpen = new List<SignalInfo>();
                _lstThisBarClose = new List<SignalInfo>();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void VerifyPrice(VerifyPathEnum eVerifyPath)
        {
            float fOpen;
            float fHigh;
            float fLow;
            float fClose;

            fOpen = Open(BaseSymbolId, Offset);
            fHigh = High(BaseSymbolId, Offset);
            fLow = Low(BaseSymbolId, Offset);
            fClose = Close(BaseSymbolId, Offset);

            switch (eVerifyPath)
            {
                case VerifyPathEnum.Open_High_Low_Close:
                    for (float fPrice = fOpen; fPrice <= fHigh; fPrice = fPrice + 1)
                        _signalManager.MatchPrice(fPrice);

                    for (float fPrice = fHigh; fPrice >= fLow; fPrice = fPrice - 1)
                        _signalManager.MatchPrice(fPrice);

                    for (float fPrice = fLow; fPrice <= fClose; fPrice = fPrice + 1)
                        _signalManager.MatchPrice(fPrice);

                    break;
                case VerifyPathEnum.Open_Low_High_Close:
                    for (float fPrice = fOpen; fPrice >= fLow; fPrice = fPrice - 1)
                        _signalManager.MatchPrice(fPrice);

                    for (float fPrice = fLow; fPrice <= fHigh; fPrice = fPrice + 1)
                        _signalManager.MatchPrice(fPrice);

                    for (float fPrice = fHigh; fPrice >= fClose; fPrice = fPrice - 1)
                        _signalManager.MatchPrice(fPrice);

                    break;
            }
        }

        #endregion
    }
}
